/*
* INSANE - Interactive Structural Analysis Environment
*
* Copyright (C) 2003-2005
* Universidade Federal de Minas Gerais
* Escola de Engenharia
* Departamento de Engenharia de Estruturas
* 
* Author's email :    insane@dees.ufmg.br
* Author's website :  http://www.dees.ufmg.br/insane
* 
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or any later version.
* 
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
* 
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/
package br.ufmg.dees.insane.ui.rich.full;

import java.util.ArrayList;
import java.util.ListIterator;

import br.ufmg.dees.insane.model.disc.element.force.ElementForce;
import br.ufmg.dees.insane.model.disc.pointforce.PointForce;

/**
*A class that calculates all the internal efforts in a certain
*section of an element caused by any kind of load.
*
*@author Ceolin, Tobias & Fonseca, Flavio & Pitangueira, Roque
*@version 1.0
*@since November 2003
*/

public class Effort{
	
	/**A PointForce that contains the force applied to the initial
	*point of the element.*/
	protected PointForce actionAtInitialPoint = new PointForce();
	
	/**An ArrayList that has all the concentrated forces applied to 
	*the element.*/
	protected ArrayList concentratedForces = new ArrayList();
	
	/**An ArrayList that has all the distributed loads applied to 
	*the element.*/
	protected ArrayList distributedForces = new ArrayList();
	
	/**The given section where will be calculated the efforts.*/
	protected double section;
	
//********************************************************************************
	
	/**Constructs a Effort object that will be used to calculate the
	*the internal efforts of the element caused by the load. This element
	*will receive a force at the initial point and concentrated and 
	*distributed forces.
	*@param IF A PointForce that represents the force at the initial point.
	*@param C An ArrayList that has all the concentrated forces applied. 
	*@param D An ArrayList that has all the distributed loads applied.
	*/
	public Effort(PointForce IF, ArrayList C, ArrayList D){
		
		this.actionAtInitialPoint = IF;
		this.concentratedForces = C;
		this.distributedForces = D;
		
	};
	
	/**Constructs a Effort object that will be used to calculate the
	*the internal efforts of an element receiving a force at the initial
	*point and concentrated forces. There is no distributed loads.
	*@param IF A PointForce that represents the force at the initial point.
	*@param C An ArrayList that has all the concentrated forces applied. 
	*/
	public Effort(PointForce IF, ArrayList C){
		
		this.actionAtInitialPoint = IF;
		this.concentratedForces = C;
		this.distributedForces = null;
		
	};
	
	/**Constructs a Effort object that will be used to calculate the
	*the internal efforts of an element receiving a force at the initial
	*point. There is no concentrated or distributed loads.
	*@param IF A PointForce that represents the force at the initial point.
	*/
	public Effort(PointForce IF){
		
		this.actionAtInitialPoint = IF;
		this.concentratedForces = null;
		this.distributedForces = null;
		
	};
	
//********************************************************************************
	
	/**Sets the force at the initial point of a Effort object constructed
	*by the default constructor.
	*@param IF A PointForce that represents the force at the initial point.
	*/
	public void setActionAtInitialPoint(PointForce IF){
		
		this.actionAtInitialPoint = IF;
		
	};
	
	/**Sets the ArrayList of concentrated forces of a Effort object 
	*constructed by the default constructor.
	*@param C An ArrayList that has all the concentrated forces applied.
	*/
	public void setConcentratedForces(ArrayList C){
		
		this.concentratedForces = C;
		
	};
	
	/**Sets the ArrayList of distributed loads of a Effort object 
	*constructed by the default constructor.
	*@param D An ArrayList that has all the distributed loads applied.
	*/
	public void setDistributedForces(ArrayList D){
		
		this.distributedForces = D;
		
	};
	
//********************************************************************************
	
	/**Sets the desired section to calculate the efforts.*/
	public void setSection(double s){
		
		this.section = s;
		
	};
	
//********************************************************************************
	
	/**Returns a PoitForce that represents all the forces and 
	*moments at the section
	@return A PointForce with all the efforts at the section.*/
	public PointForce getActionAtSection( ){
		
		PointForce actionAtSection = new PointForce();
		
		actionAtSection.setCoord(section, 0, 0);
		actionAtSection.setForce(0, getActionFXAtSection());
		actionAtSection.setForce(1, getActionFYAtSection());
		actionAtSection.setForce(2, getActionFZAtSection());
		actionAtSection.setForce(3, getActionMXAtSection());
		actionAtSection.setForce(4, getActionMYAtSection());
		actionAtSection.setForce(5, getActionMZAtSection());
		
		return actionAtSection;
		
	};
	
//********************************************************************************
	
	/**Returns only the X force calculated at the section.
	@return The value of the X force.
	*/
	public double getActionFXAtSection(){
		
		PointForce pf;
		PointForce pfi;
		PointForce pff;
		ElementForce bf;
		double force;
		double VX;
		
		VX = -(actionAtInitialPoint.getForce(0));
		
		if (concentratedForces!=null){
			
			ListIterator cfs = concentratedForces.listIterator();
			while (cfs.hasNext()){
				pf = (PointForce) cfs.next();
				if (pf.getCoord().x >= section)
					force = 0;
				else
					force = -(pf.getForce(0));
			
				VX = VX + force;
			}
		}
		
		
		force = 0;
		
		
		if(distributedForces!=null){
			
			ListIterator dfs = distributedForces.listIterator();
			while (dfs.hasNext()){
				bf = (ElementForce) dfs.next();
				
				pfi = (PointForce) bf.getPointForcesList().get(0); 
				pff = (PointForce) bf.getPointForcesList().get(1);
				
				if (pfi.getCoord().x >= section)
					force = 0;
				
				double integerValue = integralCalculator(pfi, pff, section, 0);
				force = - integerValue;
				
				
				VX = VX + force;
			}
			
		}
		
		
		return VX;
		
	};
	
//********************************************************************************
	
	/**Returns only the Y force calculated at the section.
	@return The value of the Y force.
	*/
	public double getActionFYAtSection(){
		
		PointForce pf;
		PointForce pfi;
		PointForce pff;
		ElementForce bf;
		double force;
		double VY;
		
		VY = -(actionAtInitialPoint.getForce(1));
		
		if (concentratedForces!=null){
			
			ListIterator cfs = concentratedForces.listIterator();
			while (cfs.hasNext()){
				pf = (PointForce) cfs.next();
				if (pf.getCoord().x >= section)
					force = 0;
				else
					force = -(pf.getForce(1));
			
				VY = VY + force;
			}
		}
		
		
		force = 0;
		
		
		if(distributedForces!=null){
			
			ListIterator dfs = distributedForces.listIterator();
			while (dfs.hasNext()){
				bf = (ElementForce) dfs.next();
				
				pfi = (PointForce) bf.getPointForcesList().get(0); 
				pff = (PointForce) bf.getPointForcesList().get(1);
				
				if (pfi.getCoord().x >= section)
					force = 0;
				
				double integerValue = integralCalculator(pfi, pff, section, 1);
				force = - integerValue;
				
				
				VY = VY + force;
			}
			
		}
		
		return VY;
		
	};
	
//********************************************************************************
	
	/**Returns only the Z force calculated at the section.
	@return The value of the Z force.
	*/
	public double getActionFZAtSection(){
		
		PointForce pf;
		PointForce pfi;
		PointForce pff;
		ElementForce bf;
		double force;
		double VZ;
		
		VZ = -(actionAtInitialPoint.getForce(2));
		
		if (concentratedForces!=null){
			
			ListIterator cfs = concentratedForces.listIterator();
			while (cfs.hasNext()){
				pf = (PointForce) cfs.next();
				if (pf.getCoord().x >= section)
					force = 0;
				else
					force = -(pf.getForce(2));
			
				VZ = VZ + force;
			}
		}
		
		
		force = 0;
		
		
		if(distributedForces!=null){
			
			ListIterator dfs = distributedForces.listIterator();
			while (dfs.hasNext()){
				bf = (ElementForce) dfs.next();
				
				pfi = (PointForce) bf.getPointForcesList().get(0); 
				pff = (PointForce) bf.getPointForcesList().get(1);
				
				if (pfi.getCoord().x >= section)
					force = 0;
				
				double integerValue = integralCalculator(pfi, pff, section, 2);
				force = - integerValue;
				
				VZ = VZ + force;
			}
		}
		
		return VZ;
		
	};
	
//********************************************************************************
	
	/**Returns only the X moment calculated at the section.
	@return The value of the X moment.
	*/
	public double getActionMXAtSection(){
		
		PointForce pf;
		PointForce pfi;
		PointForce pff;
		ElementForce bf;
		double moment;
		double MX;
		
		MX = - (actionAtInitialPoint.getForce(3));
		
		if(concentratedForces!=null){
			
			ListIterator cfs = concentratedForces.listIterator();
			while (cfs.hasNext()){
				pf = (PointForce) cfs.next();
				if (pf.getCoord().x >= section)
					moment = 0;
				else
					moment = - (pf.getForce(3));
				
				MX = MX + moment;
			}
		}
		
		
		moment = 0;
		
		
		if(distributedForces!=null){
			
			ListIterator dfs = distributedForces.listIterator();
			while (dfs.hasNext()){
				bf = (ElementForce) dfs.next();
				
				pfi = (PointForce) bf.getPointForcesList().get(0); 
				pff = (PointForce) bf.getPointForcesList().get(1);
				
				if (pfi.getCoord().x >= section)
					moment = 0;
				
				double integerValue = integralCalculator(pfi, pff, section, 3);
				moment = - integerValue;
				
				
				MX = MX + moment;
			}
		}
		
		return MX;
		
	};
	
//********************************************************************************
	
	/**Returns only the Y moment calculated at the section.
	@return The value of the Y moment.
	*/
	public double getActionMYAtSection(){
		
		PointForce pf;
		PointForce pfi;
		PointForce pff;
		ElementForce bf;
		double moment;
		double MY;
		
		MY = -( (actionAtInitialPoint.getForce(4)) + (actionAtInitialPoint.getForce(2) * section) );
		
		if (concentratedForces!=null){
			
			ListIterator cfs = concentratedForces.listIterator();
			while (cfs.hasNext()){
				pf = (PointForce) cfs.next();
				if (pf.getCoord().x >= section)
					moment = 0;
				else
					moment = - ( (pf.getForce(4)) + ( pf.getForce(2) * (section - pf.getCoord().x) ) );
				
				MY = MY + moment;
			}
		}
		
		
		moment = 0;
		
		
		if(distributedForces!=null){
			
			ListIterator dfs = distributedForces.listIterator();
			while (dfs.hasNext()){
				bf = (ElementForce) dfs.next();
				
				pfi = (PointForce) bf.getPointForcesList().get(0); 
				pff = (PointForce) bf.getPointForcesList().get(1);
				
				if (pfi.getCoord().x >= section) {
					moment = 0;
				} else {
					double integerValue = integralCalculator(pfi, pff, section, 2);
					double position = positionCalculator(pfi, pff, section, 2);
					moment = integerValue * position;
				}
				
				MY = MY + moment;
			}
		}
		
		return MY;
		
	};
	
//********************************************************************************
	
	/**Returns only the Z moment calculated at the section.
	@return The value of the Z moment.
	*/
	public double getActionMZAtSection(){
		
		PointForce pf;
		PointForce pfi;
		PointForce pff;
		ElementForce bf;
		double moment;
		double MZ;
		
		MZ = -( (actionAtInitialPoint.getForce(5)) - (actionAtInitialPoint.getForce(1) * section) );
		
		if (concentratedForces!=null)  {
			
			ListIterator cfs = concentratedForces.listIterator();
			while (cfs.hasNext()){
				pf = (PointForce) cfs.next();
				if (pf.getCoord().x >= section)
					moment = 0;
				else
					moment = - ( (pf.getForce(5)) - ( pf.getForce(1) * (section - pf.getCoord().x) ) );
				
				MZ = MZ + moment;
			}
		}
		
		
		moment = 0;
		
		if(distributedForces!=null){
			
			ListIterator dfs = distributedForces.listIterator();
			while (dfs.hasNext()){
				bf = (ElementForce) dfs.next();
				
				pfi = (PointForce) bf.getPointForcesList().get(0); 
				pff = (PointForce) bf.getPointForcesList().get(1);
				
				if (pfi.getCoord().x >= section) {
					moment = 0;
				} else {
					double integerValue = integralCalculator(pfi, pff, section, 1);
					double position = positionCalculator(pfi, pff, section, 1);
					moment = integerValue * position;
				}
				
				MZ = MZ + moment;
			}
		}
		
		return MZ;
		
	};
	
//********************************************************************************
	
	/**Calculates the value of the force that represents a distributed load
	composed by two PointForces, either the complete load or part of it.
	@param p1 The initial point of the considered load.
	@param p2 The final point of the considered load.
	@param section The coordinate of end to be considered of the distributed force.
	@param forceIndex The index of the force to be considered: Fx=0, Fy=1, Fz=2, Mx=3, My=4, Mz=5
	@return The value of the force.
	*/
	private double integralCalculator(PointForce p1, PointForce p2, double section, int forceIndex){
		
		double f1 = p1.getForce(forceIndex);
		double f2 = p2.getForce(forceIndex);
		double x1 = p1.getCoord().x;
		double x2 = p2.getCoord().x;
		
		double integerF = 0;
		
		if (f1!=0 || f2!=0) {
			double f3 = 0;
			double x3 = 0;
			if (section < x2) {
				double a = (f2 - f1) / (x2 - x1);
				double b = f1 - a * x1;
				f3 = a * section + b;
				x3 = section;
			}
			else {
				f3 = p2.getForce(forceIndex);
				x3 = p2.getCoord().x;
			}
			
			integerF = (f1 + f3) * (x3 - x1) / 2;
		}
		
		return integerF;
		
	};
	
//********************************************************************************
	
	/**Calculates the position of the force that represents a distributed load
	* in relation to a given section, either the complete load or part of it.
	@param p1 The initial point of the considered load.
	@param p2 The final point of the considered load.
	@param section The coordinate of end to be considered of the distributed force.
	@param forceIndex The index of the force to be considered: Fx=0, Fy=1, Fz=2, Mx=3, My=4, Mz=5
	@return The position of the representative force.
	*/
	private double positionCalculator(PointForce p1, PointForce p2, double section, int forceIndex){
		
		double f1 = p1.getForce(forceIndex);
		double f2 = p2.getForce(forceIndex);
		double x1 = p1.getCoord().x;
		double x2 = p2.getCoord().x;
		
		double f3 = 0;
		double x3 = 0;
		double extra;
		double position = 0;
		
		if (section < x2) {
			double a = (f2 - f1) / (x2 - x1);
			double b = f1 - a * x1;
			f3 = a * section + b;
			x3 = section;
			extra = 0;
		}
		else {
			f3 = p2.getForce(forceIndex);
			x3 = p2.getCoord().x;
			extra = section - x3;
		}
		
		if (f1!=0 || f3!=0) {
			position = (2 * f1 + f3) / (f1 + f3) * (x3 - x1) / 3 + extra;
		}
		
		return position;
		
	};
	
//********************************************************************************

}
